home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 301-325 / disk_313 / uucp / uucp1.lzh / src / sendmail / sendmail.c < prev   
C/C++ Source or Header  |  1990-01-25  |  22KB  |  1,043 lines

  1.  
  2. /*
  3.  *  SENDMAIL / RMAIL
  4.  *
  5.  *  (C) Copyright 1989-1990 by Matthew Dillon,  All Rights Reserved.
  6.  *
  7.  *  SENDMAIL <file -f from -t to -s subject -c cc -b bcc -r
  8.  *  RMAIL user
  9.  *
  10.  *  Example:    Sendmail <datafile -froot
  11.  *
  12.  *  From: line is automatically added but can be overriden by a From:
  13.  *  header in the file.  stdin is made up of a list of headers, a blank
  14.  *  line, and then data until EOF.
  15.  *
  16.  *  the -r option tells sendmail that this is incomming mail.
  17.  *  If av[0] begins with an 'r' for RMail instead of an 's' for
  18.  *  Sendmail, then the rmail argument format is used (rmail user),
  19.  *  as well as forcing -r.
  20.  */
  21.  
  22. #include <exec/types.h>
  23. #include <exec/lists.h>
  24. #include <proto/all.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <log.h>
  29. #include <config.h>
  30. #include <time.h>
  31. #include <pwd.h>
  32. #include <string.h>
  33. #include "/version.h"
  34.  
  35. #define RCVR_UUCP    1
  36. #define RCVR_SENDMAIL    2
  37.  
  38. IDENT(".03");
  39.  
  40. typedef struct List    LIST;
  41. typedef struct Node    NODE;
  42.  
  43. char    *UserName;
  44. char    *NodeName;
  45. char    *DomainName;
  46. char    *TimeZoneName;    /*  All caps, ex: PST             */
  47. char    *DefaultNode;    /*  for addr formats we don't understand */
  48. LIST    RecvList;    /*  Received:        */
  49. LIST    FromList;    /*  last one rules  */
  50. LIST    ToList;     /*  To:         */
  51. LIST    CcList;     /*  Cc:         */
  52. LIST    BccList;    /*  Bcc:        */
  53. LIST    XccList;    /*  list of actual mail to be sent  */
  54. LIST    SubjList;    /*  Subject:        */
  55. LIST    HdrList;    /*  other headers not specifically parsed */
  56. char    ScrBuf[1024];
  57. char    ScrBuf2[1024];
  58. char    TempFileBuf[256];
  59. int    Seq;        /*  UUCP sequence no    */
  60. char    ROpt;        /*  Receive-Mail flag    */
  61. static char OrigFromLine[512];
  62. static char FromLine[512];  /*    'From ' line, if ROpt   */
  63.  
  64. char    *TmpFileName();
  65. char    *atime();
  66. void    PostPend();
  67. void    MakeToFixNode();
  68. void    MakeToAddrNode();
  69. void    ToFixup();
  70. void    FromFixup();
  71. void    DumpHeaderInfo();
  72. void    DumpHeader();
  73. void    DumpCombineHeader();
  74. void    IntegrateHeader();
  75. void    Usage();
  76. FILE    *SendMailTo();
  77. FILE    *OneMailTo();
  78. FILE    *OneMailToUUCP();
  79. FILE    *OneMailToUser();
  80. FILE    *OneMailToFile();
  81. FILE    *OneMailToPipe();
  82. NODE    *FindHeader();
  83. NODE    *MakeNode();
  84.  
  85. CXBRK()
  86. {
  87.     return(0);
  88. }
  89.  
  90. void
  91. Usage()
  92. {
  93.     printf(
  94.     "Sendmail -f user [-t address -c address -b address -s subject -r]\n"
  95.     "RMail user\n"
  96.     );
  97. }
  98.  
  99. void
  100. main(ac, av)
  101. char *av[];
  102. {
  103.     short isRMail = 0;
  104.     short isSendMail = 1;
  105.     FILE *fi;
  106.  
  107.     NewList(&RecvList);
  108.     NewList(&FromList);
  109.     NewList(&ToList);
  110.     NewList(&CcList);
  111.     NewList(&BccList);
  112.     NewList(&XccList);
  113.     NewList(&SubjList);
  114.     NewList(&HdrList);
  115.  
  116.     UserName = FindConfig("UserName");
  117.     if (UserName == NULL) {
  118.     puts("Sendmail: UserName not in UULIB:Config!");
  119.     exit(1);
  120.     }
  121.     NodeName = FindConfig("NodeName");
  122.     if (NodeName == NULL) {
  123.     puts("Sendmail: NodeName not in UULIB:Config!");
  124.     exit(1);
  125.     }
  126.     DomainName = FindConfig("DomainName");
  127.     if (DomainName == NULL) {
  128.     puts("Sendmail: DomainName not in UULIB:Config! using .UUCP");
  129.     DomainName = ".UUCP";
  130.     }
  131.     DefaultNode = FindConfig("DefaultNode");
  132.     TimeZoneName = FindConfig("TimeZone");
  133.  
  134.     LoadAliases();
  135.  
  136.     {
  137.     char *ptr = av[0] + strlen(av[0]);
  138.  
  139.     /*
  140.      *  Skip path
  141.      */
  142.  
  143.     while (ptr >= av[0] && *ptr != ':' && *ptr != '/')
  144.         --ptr;
  145.     ++ptr;
  146.  
  147.     if (*ptr == 'r' || *ptr == 'R') {
  148.         isRMail = 1;
  149.         isSendMail = 0;
  150.     }
  151.     }
  152.  
  153.     if (isRMail) {
  154.     char *addr = (ac == 2) ? av[1] : "Mailer-Daemon";
  155.  
  156.     MakeNode(&BccList, addr);
  157.     UserName = "postmaster";    /*  XXX  */
  158.     ROpt = 1;            /*    no header processing */
  159.     }
  160.     if (isSendMail) {
  161.     short i;
  162.     char *arg;
  163.     for (i = 1; i < ac; ++i) {
  164.         arg = av[i];
  165.         if (*arg != '-')
  166.         Usage();
  167.         switch(arg[1]) {
  168.         case 'f':
  169.         UserName = av[i+1];
  170.         sprintf(ScrBuf, "%s@%s%s", av[i+1], NodeName, DomainName);
  171.         MakeNode(&FromList, ScrBuf);
  172.         ++i;
  173.         break;
  174.         case 't':
  175.         MakeNode(&ToList, av[++i]);
  176.         break;
  177.         case 'c':
  178.         MakeNode(&CcList, av[++i]);
  179.         break;
  180.         case 'b':
  181.         MakeNode(&BccList, av[++i]);
  182.         break;
  183.         case 's':
  184.         MakeNode(&SubjList, av[++i]);
  185.         break;
  186.         case 'r':
  187.         ++ROpt;
  188.         break;
  189.         default:
  190.         Usage();
  191.         }
  192.     }
  193.     }
  194.  
  195.     /*
  196.      *    Read headers from input file.  Headers are not necessarily
  197.      *    contained on a single line.  Maximum 4096 chars per header.
  198.      */
  199.  
  200.     if (ROpt) {
  201.     fgets(ScrBuf, sizeof(ScrBuf), stdin);
  202.     strcpy(OrigFromLine, ScrBuf);
  203.     if (strncmp(ScrBuf, "From ", 5) != 0) {
  204.         ulog(-1, "Receive mail, expected 'From ', got %s", ScrBuf);
  205.     }
  206.     strcpy(FromLine, "From ");
  207.     PostPend(ScrBuf + 5, 1);
  208.  
  209.     while (fgets(ScrBuf, sizeof(ScrBuf), stdin) && strncmp(ScrBuf, ">From ", 6) == 0) {
  210.         strcpy(OrigFromLine, ScrBuf + 1);
  211.         PostPend(ScrBuf + 6, 1);
  212.     }
  213.     strcpy(ScrBuf2, OrigFromLine + 5);
  214.     PostPend(ScrBuf2, 0);
  215.     } else {
  216.     ScrBuf[0] = '\n';
  217.     fgets(ScrBuf, sizeof(ScrBuf), stdin);
  218.     }
  219.     {
  220.     static char Hdr[4096];
  221.     short i = 0;        /*  index into Hdr  */
  222.  
  223.     while (ScrBuf[0] != '\n') {
  224.         char *ptr = ScrBuf;
  225.         while (*ptr && *ptr != ' ' && *ptr != 9 && *ptr != ':')
  226.         ++ptr;
  227.         if (*ptr == ':') {  /*  found new header */
  228.         if (i)          /*  Dump old header  */
  229.             IntegrateHeader(Hdr, i);
  230.         strcpy(Hdr, ScrBuf);
  231.         i = strlen(Hdr);
  232.         } else {        /*  append to existing header    */
  233.         if (i == 0)
  234.             puts("Expected a Header!");
  235.         strcpy(Hdr + i, ScrBuf);
  236.         i = i + strlen(Hdr + i);
  237.         }
  238.  
  239.         if (fgets(ScrBuf, sizeof(ScrBuf), stdin) == NULL)
  240.         ScrBuf[0] = '\n';
  241.     }
  242.     if (i)
  243.         IntegrateHeader(Hdr, i);
  244.  
  245.     if (ScrBuf[0] != '\n') {
  246.         puts("sendmail: no mail");
  247.         exit(1);
  248.     }
  249.     }
  250.  
  251.     /*
  252.      *    Parse & fixup each To:, Cc:, and Bcc: field.
  253.      *
  254.      *    From:    we add the personal info arg from the password file
  255.      *    To:    we expand any aliases
  256.      */
  257.  
  258.     if (ROpt == 0)
  259.     FromFixup(&FromList);
  260.     if (ROpt) {
  261.     ToFixup(&BccList);
  262.     } else {
  263.     ToFixup(&ToList);
  264.     ToFixup(&CcList);
  265.     ToFixup(&BccList);
  266.     }
  267.  
  268.     /*
  269.      *    If no Subject: field add a dummy one
  270.      */
  271.  
  272.     if (EmptyList(&SubjList))
  273.     MakeNode(&SubjList, "");
  274.  
  275.     if (EmptyList(&FromList)) {
  276.     sprintf(ScrBuf, "%s@%s%s", UserName, NodeName, DomainName);
  277.     MakeNode(&FromList, ScrBuf);
  278.     }
  279.  
  280.     fi = SendMailTo(&XccList, stdin);
  281.     if (fi && fi != stdin)
  282.     fclose(fi);
  283.     if (TempFileBuf[0])
  284.     remove(TempFileBuf);
  285.     UnLockFiles();
  286. }
  287.  
  288. /*
  289.  *  Strips string and creates named node which is appended to the
  290.  *  given list.
  291.  */
  292.  
  293. NODE *
  294. MakeNode(list, str)
  295. LIST *list;
  296. char *str;
  297. {
  298.     NODE *node;
  299.     char *ptr;
  300.  
  301.     while (*str == ' ' || *str == 9)
  302.     ++str;
  303.     for (ptr = str + strlen(str); ptr >= str && (*ptr == ' ' || *ptr == 9); --ptr);
  304.     ++ptr;
  305.     *ptr = 0;
  306.     node = malloc(sizeof(NODE) + strlen(str) + 1);
  307.     node->ln_Name = (char *)(node + 1);
  308.     strcpy(node->ln_Name, str);
  309.     AddTail(list, node);
  310.     return(node);
  311. }
  312.  
  313. /*
  314.  *
  315.  */
  316.  
  317. void
  318. MakeToFixNode(list, str, send)
  319. LIST *list;
  320. char *str;
  321. char *send;
  322. {
  323.     char *ptr;
  324.     short len;
  325.     short c;
  326.     void fixCallBack();
  327.  
  328.     while (str < send && (*str == ' ' || *str == 9))
  329.     ++str;
  330.     for (ptr = send - 1; ptr >= str && (*ptr == ' ' || *ptr == 9); --ptr);
  331.     ++ptr;
  332.  
  333.     len = ptr - str;
  334.     if (len < 0)
  335.     return;
  336.  
  337.     /*
  338.      *    str[0..len-1]
  339.      */
  340.  
  341.     c = str[len];
  342.     str[len] = 0;
  343.  
  344.     if (ROpt) {     /*  disallow remote asking for special options */
  345.     ulog(-1, "Received mail for %s", str);
  346.     if (str[0] == '>' || str[0] == '<' || str[0] == '|' || str[0] == ':' || str[0] == '/') {
  347.         ulog(-1, "SendMail, bad user %s", str);
  348.         return;
  349.     }
  350.     }
  351.  
  352.     {
  353.     NODE *node = malloc(sizeof(NODE) + strlen(str) + 1);
  354.  
  355.     node->ln_Name = (char *)(node + 1);
  356.     strcpy(node->ln_Name, str);
  357.     AddTail(list, node);
  358.     }
  359.  
  360.     UserAliasList(str, fixCallBack);    /*  from lib/alias.c    */
  361.     str[len] = c;
  362. }
  363.  
  364. void
  365. fixCallBack(user)
  366. char *user;
  367. {
  368.     NODE    *node;
  369.  
  370.     if (user[0] == '<') {
  371.     FILE *fi = fopen(user + 1, "r");
  372.     char *buf = malloc(256);
  373.  
  374.     if (fi == NULL) {
  375.         ulog(-1, "Unable to open < file %s", user + 1);
  376.         return;
  377.     }
  378.     while (fgets(buf, 256, fi)) {
  379.         short i = 0;
  380.         short j;
  381.         while (buf[i] == ' ' || buf[i] == 9)
  382.         ++i;
  383.         if (buf[i] == 0 || buf[i] == '\n')
  384.         continue;
  385.         for (j = i; buf[j] && buf[j] != '\n' && buf[j] != ' ' && buf[j] != 9; ++j);
  386.         buf[j] = 0;
  387.         UserAliasList(buf, fixCallBack);
  388.     }
  389.     fclose(fi);
  390.     free(buf);
  391.     return;
  392.     }
  393.  
  394.     ulog(-1, "Sendmail, Sending mail to %s", user);
  395.  
  396.     if (user[0] == '\\')
  397.     ++user;
  398.  
  399.     node = malloc(sizeof(NODE) + strlen(user) + 1);
  400.     node->ln_Name = (char *)(node + 1);
  401.     strcpy(node->ln_Name, user);
  402.     AddTail(&XccList, node);
  403. }
  404.  
  405.  
  406. /*
  407.  *  Integrates a header
  408.  */
  409.  
  410. void
  411. IntegrateHeader(hdr, len)
  412. char *hdr;
  413. short len;
  414. {
  415.     if (hdr[len-1] == '\n')     /*  strip trailing newline  */
  416.     hdr[len-1] = 0;
  417.  
  418.     if (strncmp(hdr, "From:", 5) == 0) {
  419.     MakeNode(&FromList, hdr + 5);
  420.     return;
  421.     }
  422.     if (strncmp(hdr, "To:", 3) == 0) {
  423.     MakeNode(&ToList, hdr + 3);
  424.     return;
  425.     }
  426.     if (strncmp(hdr, "Cc:", 3) == 0) {
  427.     MakeNode(&CcList, hdr + 3);
  428.     return;
  429.     }
  430.     if (strncmp(hdr, "Bcc:", 4) == 0) {
  431.     MakeNode(&BccList, hdr + 4);
  432.     return;
  433.     }
  434.     if (strncmp(hdr, "Subject:", 8) == 0) {
  435.     MakeNode(&SubjList, hdr + 8);
  436.     return;
  437.     }
  438.     if (strncmp(hdr, "Received:", 9) == 0) {
  439.     MakeNode(&RecvList, hdr + 9);
  440.     return;
  441.     }
  442.     MakeNode(&HdrList, hdr);
  443. }
  444.  
  445. /*
  446.  *  Adds (personal info) to FromList based on passwd entry or, if
  447.  *  that is not available, from the Config entry 'RealName'.
  448.  */
  449.  
  450. void
  451. FromFixup(list)
  452. LIST *list;
  453. {
  454.     char *wholeName = GetConfig("RealName", "Who Knows");
  455.     NODE *node;
  456.     NODE *nn;
  457.     LIST tmpList;
  458.  
  459.     NewList(&tmpList);
  460.  
  461.     while (node = RemHead(list)) {
  462.     /*
  463.      *  FIXME.  Fix getpwnam() and use pw_gecos entry.
  464.      */
  465.     nn = malloc(sizeof(NODE) + strlen(node->ln_Name) + strlen(wholeName) + 16);
  466.     nn->ln_Name = (char *)(nn + 1);
  467.     sprintf(nn->ln_Name, "%s (%s)", node->ln_Name, wholeName);
  468.     free(node);
  469.     AddTail(&tmpList, nn);
  470.     }
  471.     while (node = RemHead(&tmpList))
  472.     AddTail(list, node);
  473. }
  474.  
  475. /*
  476.  *  Converts an unparsed list of names into a list of single address
  477.  *  fields, removing any personal idents from the entries.  These will
  478.  *  be recombined after processing when the data file is written out.
  479.  *
  480.  *  Also expands sendmail aliases (UULIB:Aliases) (HACK)
  481.  */
  482.  
  483. void
  484. ToFixup(list)
  485. LIST *list;
  486. {
  487.     NODE *node;
  488.     LIST tmpList;
  489.  
  490.     NewList(&tmpList);
  491.  
  492.     while (node = RemHead(list)) {
  493.     char *str = node->ln_Name;
  494.     char *ptr;
  495.  
  496.     while (*str) {      /*  breakup fields by newline or comma */
  497.         for (ptr = str; *ptr && *ptr != '\n' && *ptr != ','; ++ptr);
  498.         MakeToAddrNode(&tmpList, str);
  499.         str = ptr;
  500.         while (*str == '\n' || *str == ',' || *str == ' ' || *str == 9)
  501.         ++str;
  502.     }
  503.     free(node);
  504.     }
  505.     while (node = RemHead(&tmpList))
  506.     AddTail(list, node);
  507. }
  508.  
  509. /*
  510.  *  Extracts a single name / address (comma or newline delimited)
  511.  *  field and creates a new node.
  512.  */
  513.  
  514. void
  515. MakeToAddrNode(list, str)
  516. LIST *list;
  517. char *str;
  518. {
  519.     char *p1, *p2;
  520.     short ns = 0;    /*  non-whitespace encountered */
  521.  
  522.     for (p1 = str; *p1 && *p1 != ',' && *p1 != '\n'; ++p1) {
  523.     if (*p1 == '(') {   /*  addr (name) OR (name) addr */
  524.         if (ns) {       /*  addr (name) */
  525.         MakeToFixNode(list, str, p1);
  526.         } else {
  527.         while (*p1 && *p1 != ',' && *p1 != '\n' && *p1 != ')')
  528.             ++p1;
  529.         if (*p1 == ')') {
  530.             for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n'; ++p2);
  531.             MakeToFixNode(list, p1 + 1, p2);
  532.         }
  533.         }
  534.         return;
  535.     }
  536.  
  537.     if (*p1 == '<') {   /*  <addr>  */
  538.         for (p2 = p1 + 1; *p2 && *p2 != ',' && *p2 != '\n' && *p2 != '>'; ++p2);
  539.         if (*p2 == '>')
  540.         MakeToFixNode(list, p1 + 1, p2);
  541.         return;
  542.     }
  543.     if (*p1 != ' ' && *p1 != 9)
  544.         ns = 1;
  545.     }
  546.     MakeToFixNode(list, str, p1);
  547. }
  548.  
  549.  
  550. /*
  551.  *  Send mail to <recipeant>
  552.  *
  553.  *    -Local mail
  554.  *    -Machine path (UUCP)
  555.  */
  556.  
  557. FILE *
  558. SendMailTo(list, fi)
  559. LIST *list;
  560. FILE *fi;
  561. {
  562.     NODE *node;
  563.  
  564.     for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ)
  565.     fi = OneMailTo(node->ln_Name, fi);
  566.     return(fi);
  567. }
  568.  
  569. FILE *
  570. OneMailTo(toaddr, rfi)
  571. char *toaddr;
  572. FILE *rfi;
  573. {
  574.     short i;
  575.     char c;
  576.     static char Buf[256];
  577.     static char typeBuf[16];
  578.     static char classBuf[16];
  579.     static char addrBuf[128];
  580.  
  581.     if (toaddr[0] == '|')       /*  pipe through command    */
  582.     return(OneMailToPipe(toaddr + 1, rfi));
  583.     if (toaddr[0] == '>')       /*  copy to file            */
  584.     return(OneMailToFile(toaddr + 1, rfi));
  585.  
  586.     for (i = 0; c = toaddr[i]; ++i) {
  587.     if (c == '!' || c == '%' || c == '@' || c == ':')
  588.         break;
  589.     }
  590.     if (c == 0)                 /*  local name  */
  591.     return(OneMailToUser(toaddr, rfi));
  592.  
  593.     /*
  594.      *    Non-Local mail
  595.      */
  596.  
  597.     i = ParseAddress(toaddr, Buf, strlen(toaddr));
  598.     if (DomainLookup(Buf, strlen(Buf), typeBuf, classBuf, addrBuf)) {
  599.     printf("type %s class %s addr %s\n", typeBuf, classBuf, addrBuf);
  600.     printf("buf %s\n", Buf);
  601.  
  602.     /*
  603.      *  Note distinction between mail destination and mail forwarder.
  604.      *  mail destination removes the first machine from the rmail line
  605.      *  mail forwarder does NOT
  606.      */
  607.  
  608.     if (strcmpi(classBuf, "UU") == 0) {
  609.         if (strcmpi(typeBuf, "MD") == 0)
  610.         return(OneMailToUUCP(addrBuf, Buf + i + 1, rfi));
  611.         else
  612.         return(OneMailToUUCP(addrBuf, Buf, rfi));
  613.     } else {
  614.         ulog(-1, "Unsupported domain class: %s", classBuf);
  615.         printf("Unsupported domain class: %s\n", classBuf);
  616.     }
  617.     return(rfi);
  618.     } else {
  619.     ulog(-1, "Could not find domain for %s, no mail sent", Buf);
  620.     printf("Unable to send mail to %s\n", Buf);
  621.     return(rfi);
  622.     }
  623. }
  624.  
  625.  
  626. FILE *
  627. OneMailToPipe(toaddr, rfi)
  628. char *toaddr;
  629. FILE *rfi;
  630. {
  631.     FILE *fi;
  632.     char *ptr;
  633.     static long pos;
  634.  
  635.     if (TempFileBuf[0] == 0) {
  636.     strcpy(TempFileBuf, TmpFileName("T:pipe"));
  637.     fi = fopen(TempFileBuf, "w");
  638.     if (fi == NULL) {
  639.         ulog(-1, "Unable to open temp file %s for command: %s", TempFileBuf, toaddr);
  640.         return(rfi);
  641.     }
  642.     DumpHeaderInfo(fi, RCVR_SENDMAIL, 0, 1);
  643.     pos = ftell(fi);
  644.     while (fgets(ScrBuf, sizeof(ScrBuf), rfi))
  645.         fputs(ScrBuf, fi);
  646.     fclose(fi);
  647.     }
  648.     strcpy(ScrBuf, toaddr);
  649.  
  650.     ptr = toaddr;
  651.     if (strncmpi(toaddr, "run", 3) == 0) {
  652.     ptr += 3;
  653.     while (*ptr == ' ' || *ptr == 9)
  654.         ++ptr;
  655.     }
  656.     while (*ptr && *ptr != ' ' && *ptr != 9)
  657.     ++ptr;
  658.  
  659.     if (*ptr == 0)
  660.     strcat(ScrBuf, " ");
  661.     sprintf(ScrBuf + (ptr - toaddr + 1), "<%s %s", TempFileBuf, ptr);
  662.     if (Execute(ScrBuf, NULL, NULL) == 0)
  663.     ulog(-1, "Couldn't execute %s", ScrBuf);
  664.  
  665.     fi = fopen(TempFileBuf, "r");
  666.     if (fi) {
  667.     if (rfi != stdin)
  668.         fclose(rfi);
  669.     rfi = fi;
  670.     fseek(rfi, pos, 0);
  671.     } else {
  672.     ulog(-1, "Couldn't reopen temp '%s', mail failed!", TempFileBuf);
  673.     rfi = stdin;
  674.     }
  675.     return(rfi);
  676. }
  677.  
  678. FILE *
  679. OneMailToUser(toaddr, rfi)
  680. char *toaddr;
  681. FILE *rfi;
  682. {
  683.     sprintf(ScrBuf, "UUMAIL:%s", toaddr);
  684.     return(OneMailToFile(ScrBuf, rfi));
  685. }
  686.  
  687. FILE *
  688. OneMailToFile(tofile, rfi)
  689. char *tofile;
  690. FILE *rfi;
  691. {
  692.     FILE *fo;
  693.     static char DataFile[128];
  694.     long pos;
  695.  
  696.     strcpy(DataFile, tofile);
  697.  
  698.     LockFile(DataFile);
  699.     fo = fopen(DataFile, "a");
  700.     if (fo == NULL) {
  701.     strcpy(DataFile, "T:MailOverflow");
  702.     fo = fopen(DataFile, "a");
  703.     if (fo)
  704.         ulog(-1, "Could not append to %s, appending to %s", tofile, DataFile);
  705.     else
  706.         ulog(-1, "Can't append to anywhere! (%s)", tofile);
  707.     }
  708.     if (fo) {
  709.     DumpHeaderInfo(fo, RCVR_SENDMAIL, 0, 1);
  710.     pos = ftell(fo);
  711.     if (ROpt) {
  712.         if (fgets(ScrBuf, sizeof(ScrBuf), rfi))
  713.         fputs(ScrBuf, fo);
  714.     }
  715.     while (fgets(ScrBuf, sizeof(ScrBuf), rfi)) {
  716.         if (ScrBuf[0] == 'F' && strncmp(ScrBuf, "From ", 5) == 0)
  717.         strins(ScrBuf, " ");
  718.         fputs(ScrBuf, fo);
  719.     }
  720.     fclose(fo);
  721.     if (rfi != stdin)
  722.         fclose(rfi);
  723.     rfi = fopen(DataFile, "r");
  724.     fseek(rfi, pos, 0);
  725.     }
  726.     return(rfi);
  727. }
  728.  
  729. FILE *
  730. OneMailToUUCP(toaddr, skipaddr, rfi)
  731. char *toaddr;
  732. char *skipaddr;
  733. FILE *rfi;
  734. {
  735.     static char ExecFile[128];
  736.     static char XExecFile[128];
  737.     static char CommandFile[128];
  738.     static char DataFile[128];
  739.     static char DestNode[256];
  740.     /*static char ToAddr[256];*/
  741.     FILE *fi;
  742.     int seq;
  743.     long pos;
  744.     short i;
  745.     short ai;
  746.  
  747.     /*
  748.      *    If the destination node
  749.      */
  750.  
  751.     strcpy(DestNode, toaddr);
  752.  
  753.     ai = -1;
  754.     for (i = 0; DestNode[i]; ++i) {
  755.     /*
  756.      *  Remember index for additional paths
  757.      */
  758.  
  759.     if (DestNode[i] == '!') {
  760.         DestNode[i] = 0;
  761.         ai = i + 1;
  762.         break;
  763.     }
  764.  
  765.     /*
  766.      *  Cut off machine name at 7 chars and ignore any domain
  767.      *  info.
  768.      */
  769.  
  770.     if (i == 7 || DestNode[i] == '.')
  771.         DestNode[i] = 0;
  772.     }
  773.  
  774.     Seq = seq = GetSequence(4);
  775.  
  776. #define FOFF    8
  777.  
  778.     sprintf(ExecFile,   "UUSPOOL:D.%sX%04d", DestNode, seq++);
  779.     sprintf(XExecFile,  "UUSPOOL:X.%sX%04d", DestNode, seq++);
  780.     sprintf(CommandFile,"UUSPOOL:C.%sA%04d", DestNode, seq++);
  781.     sprintf(DataFile,   "UUSPOOL:D.%sB%04d", DestNode, seq);
  782.  
  783.     LockFile(ExecFile);
  784.     LockFile(XExecFile);
  785.     LockFile(CommandFile);
  786.     LockFile(DataFile);
  787.  
  788.     /*
  789.      *    Note, cannot run uuxqt from sendmail as uuxqt may call
  790.      *    sendmail!
  791.      */
  792.  
  793.     if (strncmp(DestNode, NodeName, 7) == 0)
  794.     fi = fopen(XExecFile, "w");
  795.     else
  796.     fi = fopen(ExecFile, "w");
  797.  
  798.     if (fi == NULL)
  799.     goto fail;
  800.  
  801.     fprintf(fi, "U %s\n", UserName);
  802.     fprintf(fi, "F %s\n", DataFile + FOFF);
  803.     fprintf(fi, "I %s\n", DataFile + FOFF);
  804.     if (ai >= 0)
  805.     fprintf(fi, "C rmail %s!%s\n", DestNode + ai, skipaddr);
  806.     else
  807.     fprintf(fi, "C rmail %s\n", skipaddr);
  808.     fclose(fi);
  809.  
  810.     if (strncmp(DestNode, NodeName, 7)) {
  811.     fi = fopen(CommandFile, "w");
  812.     if (fi == NULL)
  813.         goto fail;
  814.  
  815.     fprintf(fi, "S %s %s %s - %s 0666\n", DataFile + FOFF, DataFile + FOFF, UserName, DataFile + FOFF);
  816.     fprintf(fi, "S %s %s %s - %s 0666\n", ExecFile + FOFF, XExecFile + FOFF, UserName, ExecFile + FOFF);
  817.     fclose(fi);
  818.     }
  819.  
  820.     fi = fopen(DataFile, "w");
  821.     if (fi == NULL)
  822.     goto fail;
  823.  
  824.     DumpHeaderInfo(fi, RCVR_UUCP, 1, 0);
  825.     pos = ftell(fi);
  826.  
  827.     if (ROpt) {
  828.     if (fgets(ScrBuf, sizeof(ScrBuf), rfi))
  829.         fputs(ScrBuf, fi);
  830.     }
  831.     while (fgets(ScrBuf, sizeof(ScrBuf), rfi)) {
  832.     if (ScrBuf[0] == 'F' && strncmp(ScrBuf, "From ", 5) == 0)
  833.         strins(ScrBuf, " ");
  834.     fputs(ScrBuf, fi);
  835.     }
  836.     fclose(fi);
  837.     if (rfi != stdin)
  838.     fclose(rfi);
  839.     fi = fopen(DataFile, "r");
  840.     fseek(fi, pos, 0);
  841.     return(fi);
  842. fail:
  843.     puts("Fail");
  844.     return(rfi);
  845. }
  846.  
  847. void
  848. DumpHeaderInfo(fi, rcvr, resend, local)
  849. FILE *fi;
  850. {
  851.     char *source;
  852.     time_t t;
  853.  
  854.     time(&t);
  855.  
  856.     /*
  857.      *    Write header info
  858.      */
  859.  
  860.     if (rcvr == RCVR_UUCP)
  861.     source = "AmigaUUCP";
  862.     else
  863.     source = "Sendmail";
  864.  
  865.     if (ROpt) {
  866.     if (resend)
  867.         fprintf(fi, "%s %s remote from %s\n", FromLine, atime(&t), NodeName);
  868.     else
  869.         fprintf(fi, "%s %s\n", FromLine, atime(&t));
  870.     } else {
  871.     if (local)
  872.         fprintf(fi, "From %s %s\n", UserName, atime(&t));
  873.     else
  874.         fprintf(fi, "From %s %s remote from %s\n", UserName, atime(&t), NodeName);
  875.     }
  876.     fprintf(fi, "Received: by %s%s (0.44/0.44)\n\tid AA%05d; %s\n",
  877.     NodeName, DomainName, Seq, atime(&t)
  878.     );
  879.     DumpHeader(fi, "Received:", &RecvList);
  880.     if (ROpt == 0) {
  881.     time_t t2 = t + 3600 * GetHourOffset(TimeZoneName);
  882.     struct tm *ut;
  883.  
  884.     if (FindHeader("Date:") == NULL)
  885.         fprintf(fi, "Date: %s\n", atime(&t));
  886.     ut = localtime(&t2);
  887.     fprintf(fi, "Message-Id: <%02d%02d%02d%02d%02d.AA%05d@%s%s>\n",
  888.         ut->tm_year % 100, ut->tm_mon + 1, ut->tm_mday, ut->tm_hour, ut->tm_min,
  889.         Seq, NodeName, DomainName
  890.     );
  891.     }
  892.  
  893.     /*
  894.      *    From:, To:, Cc:, Subject: (Bcc: never written to header),
  895.      *    and any other header fields
  896.      */
  897.  
  898.     DumpHeader(fi, NULL, &HdrList);
  899.     DumpHeader(fi, "From:", &FromList);
  900.     DumpCombineHeader(fi, "To:", &ToList);
  901.     if (!EmptyList(&CcList))
  902.     DumpCombineHeader(fi, "Cc:", &CcList);
  903.     DumpHeader(fi, "Subject:", &SubjList);
  904.  
  905.     fprintf(fi, "\n");
  906. }
  907.  
  908. void
  909. DumpHeader(fi, field, list)
  910. FILE *fi;
  911. char *field;
  912. LIST *list;
  913. {
  914.     NODE *node;
  915.  
  916.     for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ) {
  917.     if (field)
  918.         fprintf(fi, "%s %s\n", field, node->ln_Name);
  919.     else
  920.         fprintf(fi, "%s\n", node->ln_Name);
  921.     }
  922. }
  923.  
  924. NODE *
  925. FindHeader(field)
  926. char *field;
  927. {
  928.     NODE *node;
  929.     short len = strlen(field);
  930.  
  931.     for (node = HdrList.lh_Head; node != (NODE *)&HdrList.lh_Tail; node = node->ln_Succ) {
  932.     if (strncmp(node->ln_Name, field, len) == 0)
  933.         return(node);
  934.     }
  935.     return(NULL);
  936. }
  937.  
  938. void
  939. DumpCombineHeader(fi, field, list)
  940. FILE *fi;
  941. char *field;
  942. LIST *list;
  943. {
  944.     NODE *node;
  945.     short ci = 0;
  946.  
  947.     fprintf(fi, "%s ", field);
  948.     for (node = list->lh_Head; node != (NODE *)&list->lh_Tail; node = node->ln_Succ) {
  949.     if (ci && ci + strlen(node->ln_Name) > 70) {
  950.         fprintf(fi, ",\n\t");
  951.         ci = 0;
  952.     }
  953.     if (ci)
  954.         fprintf(fi, ", ");
  955.     fprintf(fi, "%s", node->ln_Name);
  956.     ci += strlen(node->ln_Name) + 2;
  957.     }
  958.     fprintf(fi, "\n");
  959. }
  960.  
  961. char *
  962. atime(pt)
  963. time_t *pt;
  964. {
  965.     static char buf[40];
  966.     static char *mo[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  967.                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  968.             };
  969.     static char *dow[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  970.     struct tm *ut = localtime(pt);
  971.  
  972.     sprintf(buf, "%s, %d %s %02d %02d:%02d:%02d %s",
  973.     dow[ut->tm_wday], ut->tm_mday, mo[ut->tm_mon],
  974.     ut->tm_year % 100, ut->tm_hour, ut->tm_min, ut->tm_sec,
  975.     TimeZoneName
  976.     );
  977.     return(buf);
  978. }
  979.  
  980. GetHourOffset(tz)
  981. char *tz;
  982. {
  983.     short i;
  984.  
  985.     static struct {
  986.     char *Name;
  987.     short Hours;
  988.     } TZAry[] = {
  989.     "GMT",  0,
  990.     "UT",   0,
  991.     "PST",  8,
  992.     "MST",  7,
  993.     "CST",  6,
  994.     "EST",  5,
  995.     "AST",  4,
  996.     "PDT",  7,
  997.     "MDT",  6,
  998.     "CDT",  5,
  999.     "EDT",  4,
  1000.     "ADT",  3,
  1001.     NULL, 0
  1002.     };
  1003.     for (i = 0; TZAry[i].Name; ++i) {
  1004.     if (strncmp(tz, TZAry[i].Name, 3) == 0)
  1005.         return((int)TZAry[i].Hours);
  1006.     }
  1007.     ulog(-1, "Unknown Timezone: %s", tz);
  1008.     printf("Unknown Timezone: %s", tz);
  1009.     return(6);
  1010. }
  1011.  
  1012. void
  1013. PostPend(str, frend)
  1014. char *str;
  1015. {
  1016.     char *ptr;
  1017.     if (frend) {
  1018.     ptr = str + strlen(str);
  1019.     while (ptr > str && *ptr != ' ' && *ptr != 9) {
  1020.         if (*ptr == '\n')
  1021.         *ptr = 0;
  1022.         --ptr;
  1023.     }
  1024.     str = ptr + 1;
  1025.     }
  1026.     for (ptr = str; *ptr && *ptr != ' ' && *ptr != 9 && *ptr != '\n'; ++ptr);
  1027.     if (frend)
  1028.     strcpy(ptr, "!");
  1029.     else
  1030.     strcpy(ptr, "");
  1031.     for (ptr = FromLine + 5; *ptr && *ptr != ' ' && *ptr != 9; ++ptr);
  1032.     strins(ptr, str);
  1033. }
  1034.  
  1035. EmptyList(list)
  1036. LIST *list;
  1037. {
  1038.     if (list->lh_Head == (NODE *)&list->lh_Tail)
  1039.     return(1);
  1040.     return(0);
  1041. }
  1042.  
  1043.